/**
 * @author SongJun
 * @description TODO:
 * @date 2021/9/14 10:55
 */
public class BuyAndSellStock {
    public static void main(String[] args) {
        BuyAndSellStock instance = new BuyAndSellStock();
        int[] prices = {7,1,5,3,6,4};
        System.out.println(instance.maxProfit2(prices));
    }

    /** 
     * @description
     * 给定一个数组 prices ，它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
     * 你只能选择 某一天 买入这只股票，并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
     * 返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润，返回 0 。
     * @author SongJun
     * @date 2021/9/14 11:10
     */
    public int maxProfit1(int prices[]) {
        int minprice = Integer.MAX_VALUE;
        int maxprofit = 0;
        //如果最优的结果是在第b天买入, 第s天卖出. 那么第b天一定是第s天之前的历史最低点, 且第s天是第b天之后的历史最高点
        for (int i = 0; i < prices.length; i++) {
            if (prices[i] < minprice) {
                minprice = prices[i];
            } else if (prices[i] - minprice > maxprofit) {
                maxprofit = prices[i] - minprice;
            }
        }
        return maxprofit;
    }

    /** 
     * @description
     * 给定一个数组 prices ，其中 prices[i] 是一支给定股票第 i 天的价格。
     * 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易（多次买卖一支股票）。
     * 注意：你不能同时参与多笔交易（你必须在再次购买前出售掉之前的股票）。
     *
     * @author SongJun
     * @date 2021/9/14 14:18
     */
    public int maxProfit2(int prices[]) {
        int n = prices.length;
        int[][] dp = new int[n][2];
        //dp[i][0]表示第i天未持有股票所获得的最大利润
        for (int i = 0; i < n; i++) {
            if(i==0){
                dp[i][0]=0;
                dp[i][1]=-prices[i];
                continue;
            }
            dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] + prices[i]);
            dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] - prices[i]);
        }
        return dp[n - 1][0];
    }


}
